﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Authentication;
using System.ServiceModel;
using System.Text;
using Agatha.Common;
using Agatha.Common.InversionOfControl;
using Agatha.ServiceLayer;
using Source.Common;

namespace Source.ServiceLayer
{
  
    public abstract class NhRequestHandler<TRequest, TResponse> : RequestHandler<TRequest, TResponse>
        where TRequest : Request
        where TResponse : Response
    {

        public IUnitOfWork UnitOfWork { get; set; }
        public IAuthenticationManager AuthenticationManager { get; set; }
        public IServerSideUserManager UserManager { get; set; }
        public ILogManager LogManager { get; set; }

        protected override void DisposeManagedResources()
        {
            if (UnitOfWork != null) UnitOfWork.Dispose();
        }

        public override void BeforeHandle(TRequest request)
        {
            CheckAuthenticationIfApplicable( request);
        }

        public override Response Handle(Request request)
        {
                bool useUnitOfWork = !(request is ReadOnlyRequest);
                bool exceptionOccrued = false;
                
                Response response;
                ITransaction transaction = null;
                try
                {
                    if (useUnitOfWork)
                        transaction = UnitOfWork.CreateTransaction();
                    response = base.Handle(request);
                   
                }
                catch (Exception handlerException)
                {
                        exceptionOccrued = true;
                        LogManager.Error("NhRequestHandler: Rollback after exception failed! Original exception (the one that caused the rollback) was: ", handlerException);
                        throw;
                }
                finally
                {
                    if (useUnitOfWork )
                    {
                        if (!exceptionOccrued)
                            transaction.Commit();
                        else
                        {
                            transaction.Rollback();
                        }
                    }
                       
                }

                return response;

           
        }
        private void CheckAuthenticationIfApplicable(Request request)
        {
            var authenticatedRequest = request as AuthenticatedRequest;
            if (authenticatedRequest != null)
            {
                if (!AuthenticationManager.IsAuthenticated(authenticatedRequest.Visit))
                {
                    throw new AuthenticationException((MessageKeys.UserCouldNotBeAuthenticated));
                }
                UserManager.StoreCurrentVisitInfo(authenticatedRequest.Visit);
            }
        }
    }
}
